﻿using System.Collections.Concurrent;
using System.Collections.ObjectModel;
using System.Data;
using System.Diagnostics.CodeAnalysis;
using XYS.Core.Models;

namespace XYS.Core.Util;
public static partial class Extention
{
    /// <summary>
    /// 并发
    /// 使用 ConcurrentQueue+Parallel.For 实现并发
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source">数据源</param>
    /// <param name="threadCount">并发数量</param>
    /// <param name="action">执行器</param>
    public static void ParallelFor<T>(this IEnumerable<T> source, int threadCount, Action<IEnumerable<T>> action)
    {
        if (source == null || !source.Any() || threadCount <= 0 || action == null) return;
        if (threadCount == 1)
        {
            action(source);
            return;
        }

        //进入队列
        ConcurrentQueue<T> queue = new(source);

        int listCount = source.Count();
        var count = listCount / threadCount;
        if (listCount % threadCount != 0) count++;

        Parallel.For(0, threadCount, index =>
        {
            int skipCount = (int)(index * count);
            var array = queue.Skip(skipCount).Take(count);
            if (!array.IsNullOrEmpty())
                action.Invoke(array);
        });
    }

    /// <summary>
    /// 并发
    /// 使用 ConcurrentQueue+Parallel.For 实现并发
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TResult"></typeparam>
    /// <param name="source">数据源</param>
    /// <param name="threadCount">并发数量</param>
    /// <param name="action">执行器</param>
    public static TResult[] ParallelFor<T, TResult>(this IEnumerable<T> source, int threadCount, Func<IEnumerable<T>, TResult> action)
    {
        if (source == null || !source.Any() || threadCount <= 0 || action == null) return default;
        if (threadCount == 1)
            return new TResult[] { action(source) };

        //进入队列
        ConcurrentQueue<T> queue = new(source);

        int listCount = source.Count();
        var count = listCount / threadCount;
        if (listCount % threadCount != 0) count++;

        ConcurrentBag<TResult> result = new();
        Parallel.For(0, threadCount, index =>
        {
            var array = queue.Skip(index * count).Take(count);
            if (!array.IsNullOrEmpty())
            {
                result.Add(action(array));
            }
        });
        return result.ToArray();
    }

    /// <summary>
    /// 异步并发处理
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source"></param>
    /// <param name="threadCount"></param>
    /// <param name="asyncAction"></param>
    /// <returns></returns>
    public static async Task ParallelForAsync<T>(this IEnumerable<T> source, int threadCount, Func<IEnumerable<T>, Task> asyncAction)
    {
        if (source == null || !source.Any() || threadCount <= 0 || asyncAction == null) return;
        if (threadCount <= 1)
        {
            await asyncAction(source);
            return;
        }

        List<Task> tasks = new();
        int listCount = source.Count();
        var count = listCount / threadCount;
        if (listCount % threadCount != 0) count++;

        for (int i = 0; i < threadCount; i++)
        {
            var array = source.Skip(i * count).Take(count);
            if (!array.IsNullOrEmpty())
                tasks.Add(asyncAction(array));
        }
        await Task.WhenAll(tasks);
    }

    /// <summary>
    /// 异步并发处理
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TResult"></typeparam>
    /// <param name="source"></param>
    /// <param name="threadCount"></param>
    /// <param name="asyncAction"></param>
    /// <returns></returns>
    public static async Task<TResult[]> ParallelForAsync<T, TResult>(this IEnumerable<T> source, int threadCount, Func<IEnumerable<T>, Task<TResult>> asyncAction)
    {
        if (source == null || !source.Any() || threadCount <= 0 || asyncAction == null) return default;
        if (threadCount <= 1) return new TResult[] { await asyncAction(source) };

        List<Task<TResult>> tasks = new();
        int listCount = source.Count();
        var count = listCount / threadCount;
        if (listCount % threadCount != 0) count++;

        for (int i = 0; i < threadCount; i++)
        {
            var array = source.Skip(i * count).Take(count);
            if (!array.IsNullOrEmpty())
                tasks.Add(asyncAction(array));
        }
        return await Task.WhenAll(tasks);
    }




    /// <summary>
    /// 并发
    /// 使用 ConcurrentQueue+Parallel.For 实现并发
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source">数据源</param>
    /// <param name="threadCount">并发数量</param>
    /// <param name="action">执行器</param>
    public static void ParallelFors<T>(this IEnumerable<T> source, int threadCount, Action<T> action)
    {
        source.ParallelFor(threadCount, array =>
        {
            foreach (var item in array)
                action(item);
        });
    }

    /// <summary>
    /// 并发
    /// 使用 ConcurrentQueue+Parallel.For 实现并发
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TResult"></typeparam>
    /// <param name="source">数据源</param>
    /// <param name="threadCount">并发数量</param>
    /// <param name="action">执行器</param>
    public static TResult[][] ParallelFors<T, TResult>(this IEnumerable<T> source, int threadCount, Func<T, TResult> action)
    {
        return source.ParallelFor(threadCount, array =>
        {
            List<TResult> result = new();
            foreach (var item in array)
                result.Add(action(item));
            return result.ToArray();
        });
    }

    /// <summary>
    /// 异步并发处理
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source"></param>
    /// <param name="threadCount"></param>
    /// <param name="asyncAction"></param>
    /// <returns></returns>
    public static async Task ParallelForsAsync<T>(this IEnumerable<T> source, int threadCount, Func<T, Task> asyncAction)
    {
        await source.ParallelForAsync(threadCount, async array =>
        {
            foreach (var item in array)
                await asyncAction(item).ConfigureAwait(false);
        });
    }

    /// <summary>
    /// 异步并发处理
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TResult"></typeparam>
    /// <param name="source"></param>
    /// <param name="threadCount"></param>
    /// <param name="asyncAction"></param>
    /// <returns></returns>
    public static async Task<TResult[][]> ParallelForsAsync<T, TResult>(this IEnumerable<T> source, int threadCount, Func<T, Task<TResult>> asyncAction)
    {
        var res = await source.ParallelForAsync(threadCount, async array =>
        {
            List<TResult> result = new();
            foreach (var item in array)
                result.Add(await asyncAction(item).ConfigureAwait(false));
            return result.ToArray();
        });
        return res;
    }


    /// <summary>
    /// 分页查询
    /// </summary>
    /// <param name="queryable"></param>
    /// <param name="request"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static PageResult<T> ToPageList<T>(this IEnumerable<T> queryable, PageRequest request)
    where T : class
    {
        int total = 0;
        return (string.IsNullOrWhiteSpace(request.Sort) ? queryable : queryable.OrderBy(e => request.Sort + (request.IsAsc ? "" : " desc")))
        .ToPageList(request.PageNo, request.PageSize, ref total);
    }

    /// <summary>
    /// 分页查询
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="queryable"></param>
    /// <param name="pageNo"></param>
    /// <param name="pageSize"></param>
    /// <param name="total"></param>
    /// <returns></returns>
    public static PageResult<T> ToPageList<T>(this IEnumerable<T> queryable, int pageNo, int pageSize, ref int total)
    where T : class
    {
        total = queryable.Count();
        return new PageResult<T>()
        {
            List = queryable.Skip((pageNo - 1) * pageSize).Take(pageSize).ToList(),
            Total = total
        };
    }


    /// <summary>
    /// 深度复制
    /// </summary>
    /// <typeparam name="T">泛型</typeparam>
    /// <param name="iEnumberable">原数据</param>
    /// <param name="startIndex">原数据开始复制的起始位置</param>
    /// <param name="length">需要复制的数据长度</param>
    /// <returns></returns>
    public static IEnumerable<T> Clone<T>(this IEnumerable<T> iEnumberable, int startIndex, int length)
    {
        var sourceArray = iEnumberable.ToArray();
        T[] newArray = new T[length];
        Array.Copy(sourceArray, startIndex, newArray, 0, length);

        return newArray;
    }

    /// <summary>
    /// 深度复制
    /// </summary>
    /// <typeparam name="T">泛型</typeparam>
    /// <param name="iEnumberable">原数据</param>
    /// <returns></returns>
    public static IEnumerable<T> Clone<T>(this IEnumerable<T> iEnumberable)
    {
        var sourceArray = iEnumberable.ToArray();
        T[] newArray = new T[iEnumberable.Count()];
        Array.Copy(sourceArray, 0, newArray, 0, newArray.Length);

        return newArray;
    }


    /// <summary>
    /// 给IEnumerable拓展ForEach方法
    /// </summary>
    /// <typeparam name="T">模型类</typeparam>
    /// <param name="iEnumberable">数据源</param>
    /// <param name="func">方法</param>
    public static void ForEach<T>(this IEnumerable<T> iEnumberable, Action<T> func)
    {
        foreach (var item in iEnumberable)
        {
            func(item);
        }
    }

    /// <summary>
    /// 给IEnumerable拓展ForEach方法
    /// </summary>
    /// <typeparam name="T">模型类</typeparam>
    /// <param name="iEnumberable">数据源</param>
    /// <param name="func">方法</param>
    public static void ForEach<T>(this IEnumerable<T> iEnumberable, Action<T, int> func)
    {
        var array = iEnumberable.ToArray();
        for (int i = 0; i < array.Length; i++)
        {
            func(array[i], i);
        }
    }


    /// <summary>
    /// 将IEnumerable'T'转为对应的DataTable
    /// Json字符串请勿使用该扩展，请使用 JsonToDataTable
    /// </summary>
    /// <typeparam name="T">数据模型</typeparam>
    /// <param name="iEnumberable">数据源</param>
    /// <returns>DataTable</returns>
    public static DataTable ToDataTable<T>(this IEnumerable<T> iEnumberable)
    {
        return iEnumberable.ToJson().JsonToDataTable();
    }

    /// <summary>
    /// Json 字符串 转换为 DataTable数据集合
    /// </summary>
    /// <param name="json"></param>
    /// <returns></returns>
    public static DataTable JsonToDataTable(this string json)
    {
        DataTable result = new();
        try
        {
            var mapList = json.ToObject<List<Dictionary<string, object>>>();
            if (mapList.Count == 0) return result;

            var columns = mapList.SelectMany(x => x.Keys).Distinct().ToList();
            foreach (string current in columns)
                result.Columns.Add(current, mapList.First(x => x.ContainsKey(current))[current].GetType());

            foreach (Dictionary<string, object> dictionary in mapList)
            {
                //Rows
                DataRow dataRow = result.NewRow();
                foreach (string current in dictionary.Keys)
                {
                    dataRow[current] = dictionary[current];
                }
                result.Rows.Add(dataRow); //循环添加行到DataTable中
            }
        }
        catch { }
        return result;
    }



    /// <summary>
    /// ObservableCollection删除扩展
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="coll"></param>
    /// <param name="condition"></param>
    /// <returns></returns>
    public static int RemoveAll<T>(this ObservableCollection<T> coll, Func<T, bool> condition)
    {
        List<T> itemsToRemove = coll.Where(condition).ToList();

        foreach (var itemToRemove in itemsToRemove)
        {
            coll.Remove(itemToRemove);
        }

        return itemsToRemove.Count;
    }

    /// <summary>
    /// ICollection删除扩展
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="coll"></param>
    /// <param name="condition"></param>
    /// <returns></returns>
    public static int RemoveAll<T>(this ICollection<T> coll, Func<T, bool> condition)
    {
        List<T> itemsToRemove = coll.Where(condition).ToList();

        foreach (var itemToRemove in itemsToRemove)
        {
            coll.Remove(itemToRemove);
        }

        return itemsToRemove.Count;
    }

    /// <summary>
    /// 获取序列中的随机元素
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="coll"></param>
    /// <returns></returns>
    public static T Random<T>(this IEnumerable<T> coll)
    {
        if (coll == null || !coll.Any()) return default;
        int index = new Random(Guid.NewGuid().GetHashCode()).Next(0, coll.Count());
        return coll.Skip(index).First();
    }

    /// <summary>
    /// 获取序列中N个随机元素
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="coll"></param>
    /// <param name="count"></param>
    /// <returns></returns>
    public static IEnumerable<T> Random<T>(this IEnumerable<T> coll, int count)
    {
        if (coll == null) return new List<T>();
        if (!coll.Any()) return coll;
        count = count < coll.Count() ? count : coll.Count();
        List<T> ret = new();
        while (count > 0)
        {
            T re = coll.Random();
            if (!ret.Contains(re))
            {
                ret.Add(re);
                count--;
            }
        }
        return ret;
    }

    /// <summary>
    /// 判断集合是否为空
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source"></param>
    /// <returns></returns>
    public static bool IsNullOrEmpty<T>([NotNullWhen(false)] this IEnumerable<T> source)
    {
        if (source == null) return true;
        return !source.Any();
    }

    /// <summary>
    /// 根据指定字段去重
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    /// <param name="source"></param>
    /// <param name="keySelector"></param>
    /// <returns></returns>
    public static IEnumerable<TSource> Distinct<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
    {
        HashSet<TKey> seenKeys = new();
        foreach (TSource element in source)
        {
            var elementValue = keySelector(element);
            if (seenKeys.Add(elementValue))
            {
                yield return element;
            }
        }
    }


    /// <summary>
    /// 获取随机元素
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <param name="source"></param>
    /// <returns></returns>
    public static TSource GetRandomChilds<TSource>(this IEnumerable<TSource> source)
    {
        if (source == null || !source.Any()) { return default; }
        //如果只有一个 就不进行随机运算
        if (source.Count() == 1) { return source.FirstOrDefault(); }

        return source.Skip((new Random(Guid.NewGuid().GetHashCode())).Next(0, source.Count())).FirstOrDefault();
    }


    /// <summary>
    /// 差异计算，得出 添加、更新、删除 集合
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <typeparam name="TTarget"></typeparam>
    /// <param name="source"></param>
    /// <param name="target"></param>
    /// <returns></returns>
    public static EnumerableDiffModel<TSource, TTarget> EnumerableDiff<TSource, TTarget>(this IEnumerable<TSource> source, IEnumerable<TTarget> target)
    where TSource : XYS.Service.Core.Base.IIdField
    where TTarget : XYS.Service.Core.Base.IIdField
    {
        //两个集合都为空，直接返回空集合
        if (source.IsNullOrEmpty() && target.IsNullOrEmpty())
            return new EnumerableDiffModel<TSource, TTarget>();

        //原集合为空 不需要计算了则直接返回结果
        if (source.IsNullOrEmpty())
            return new EnumerableDiffModel<TSource, TTarget> { DeletedItems = target.ToList() };

        //目标集合为空 不需要计算了则直接返回结果
        if (target.IsNullOrEmpty())
            return new EnumerableDiffModel<TSource, TTarget> { AddedItems = source.ToList() };


        // 使用 HashSet 存储 Id 集合
        var sourceIdSet = new HashSet<long>(source.Select(e => e.Id));
        var targetIdSet = new HashSet<long>(target.Select(e => e.Id));

        // 原始数组有， 目标数组无（需要新建）
        List<TSource> addedItems = source.Where(x => !targetIdSet.Contains(x.Id)).ToList();

        // 并级（需要更新）
        List<TSource> updatedSourceItems = source.Where(x => targetIdSet.Contains(x.Id)).ToList();
        List<TTarget> updatedTargetItems = target.Where(x => sourceIdSet.Contains(x.Id)).ToList();

        // 原始数组无，目标数组有（需要删除）
        List<TTarget> deletedItems = target.Where(x => !sourceIdSet.Contains(x.Id)).ToList();

        return new EnumerableDiffModel<TSource, TTarget>
        {
            AddedItems = addedItems,
            UpdatedSourceItems = updatedSourceItems,
            UpdatedTargetItems = updatedTargetItems,
            DeletedItems = deletedItems
        };
    }




    /// <summary>
    /// 差异集合
    /// </summary>
    public class EnumerableDiffModel<TSource, TTarget>
        where TSource : XYS.Service.Core.Base.IIdField
        where TTarget : XYS.Service.Core.Base.IIdField
    {
        /// <summary>
        /// 原始数组有， 目标数组无（需要新建）
        /// </summary>
        public List<TSource> AddedItems { get; set; } = new List<TSource>();
        /// <summary>
        /// 并集（需要更新）
        /// </summary>
        public List<TSource> UpdatedSourceItems { get; set; } = new List<TSource>();
        /// <summary>
        /// 并集（需要更新）
        /// </summary>
        public List<TTarget> UpdatedTargetItems { get; set; } = new List<TTarget>();
        /// <summary>
        /// 原始数组无，目标数组有（需要删除）
        /// </summary>
        public List<TTarget> DeletedItems { get; set; } = new List<TTarget>();
    }

}